import { NSelect, NInput, NDatePicker, NInputNumber, NTreeSelect } from 'naive-ui'
import { type DefineComponent } from 'vue'
import type { FormConfigElement } from './shared'
import { isArray, isDefined } from './DynamicFormConfig/utils'
import { cloneDeep } from 'lodash-es'

import FishTail from './sharedComponents/FishTail.vue'
import DimensionInput from './sharedComponents/DimensionInput.vue'
import ThemeWordSelect from './sharedComponents/ThemeWordSelect.vue'
import VersionStatistics from './sharedComponents/VersionStatistics.vue'
import CollectionMethodSelect from './sharedComponents/CollectionMethodSelect.vue'
import VersionTypeCascadeSelect from './sharedComponents/VersionTypeCascadeSelect.vue'

const elements = [
  NSelect,
  NInput,
  NDatePicker,
  NInputNumber,
  NTreeSelect,
  FishTail,
  DimensionInput,
  ThemeWordSelect,
  VersionStatistics,
  CollectionMethodSelect,
  VersionTypeCascadeSelect
] as DefineComponent<unknown, unknown, null>[]
const names = elements.map((e) => e.name!)
const getElementByType = (name: string) => elements.find((e) => e.name === name) || null
console.log(names)
let uid = 1
const getUid = () => uid++

export default {
  elements,
  names,
  getElementByType,
  getUid
}

export function handleDynamicFormItemProps(config: FormConfigElement, labelSuffix?: string) {
  config = cloneDeep(config)
  if (!config.formItemProps) return null
  const rule = config.formItemProps.rule

  // 就算rule是空对象，它也会触发数据类型校验
  if (!rule || Reflect.ownKeys(rule).length === 0) config.formItemProps.rule = undefined

  if (isDefined(labelSuffix) && isDefined(config.formItemProps.label)) {
    config.formItemProps.label = config.formItemProps.label + labelSuffix
  }

  if (isDefined(rule)) {
    const tmp = isArray(rule) ? rule : [rule]
    for (let i = 0; i < tmp.length; i++) {
      const r = tmp[i]
      if (r.validator && typeof r.validator === 'string') {
        r.validator = handleStringFunc(r.validator as string)
      }
    }
  }

  return config.formItemProps as any
}

// TODO： BUG: 在formData的值发生变化时，这个函数总会被重复调用
export function handleDynamicElementProps(
  config: FormConfigElement,
  vars?: Record<string, unknown>
) {
  config = cloneDeep(config)
  if (!config.elementProps) return null
  const { onUpdateValue, value, onUpdateFormattedValue, formattedValue } = config.elementProps

  if (isDefined(onUpdateValue)) {
    config.elementProps.onUpdateValue = handleDynamicElementEventStringFunc(onUpdateValue, vars)
  }

  if (isDefined(onUpdateValue)) {
    config.elementProps.onUpdateValue = handleDynamicElementEventStringFunc(onUpdateValue, vars)
  }

  if (isDefined(onUpdateFormattedValue)) {
    config.elementProps.onUpdateFormattedValue = handleDynamicElementEventStringFunc(
      onUpdateFormattedValue,
      vars
    )
  }

  if (isDefined(formattedValue) && typeof formattedValue === 'string') {
    config.elementProps.formattedValue = handleStringFunc(formattedValue, vars)
  }

  if (isDefined(value) && typeof value === 'string') {
    config.elementProps.value = handleStringFunc(value, vars)
  }

  return config.elementProps as any
}

const handleDynamicElementEventStringFunc = (v: unknown, vars?: Record<string, unknown>) => {
  return handleStringFuncArray(isArray(v) ? v : [v], vars)
}

const handleStringFunc = (v: string, vars?: Record<string, unknown>) => {
  return new Function(`return ${v}`).call(vars)
}

const handleStringFuncArray = (v: unknown[], vars?: Record<string, unknown>) => {
  for (let i = 0; i < v.length; i++) {
    if (typeof v[i] !== 'string') continue
    v[i] = handleStringFunc(v[i] as string, vars)
  }
  return v as any[]
}
